package com.jms.tomcat.core;

import com.jms.tomcat.config.JmsTomcatConfigItem;
import com.jms.tomcat.config.TomcatConfig;
import com.jms.tomcat.handler.RequestHandler;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class JmsServletContainer {

    private static final Logger logger = LogManager.getLogger(JmsServletContainer.class);
    /**
     * 服务套接字
     */
    private ServerSocket serverSocket;
    /**
     * 处理请求线程池
     */
    private ExecutorService requestConnect;
    /**
     * servlet 环境上下文
     */
    private JmsServletContext servletContext;

    private volatile boolean running = true;

    /**
     * 容器启动方法
     * @param configClass 配置注解所在类
     * @param config 配置信息
     * @throws IOException IOException
     */
    public void start(Class<?> configClass, TomcatConfig config) throws IOException {
        //添加JVM钩子，关闭之前执行容器销毁操作
        Runtime.getRuntime().addShutdownHook(new Thread(this::dispose, "JmsTomcatShutdown"));

        servletContext = new JmsServletContext(configClass, config);

        logger.info("Server starting.");

        //获取监听端口
        int port = config.getIntegerValue(JmsTomcatConfigItem.JMS_TOMCAT_PORT.getValue());
        //获取连接池最大连接数
        int maxConnectNumber = config.getIntegerValue(JmsTomcatConfigItem.JMS_TOMCAT_MAX_CONNECT_NUMBER.getValue());
        //初始化Servlet上下文
        servletContext.init();
        //调用ServletContainerInitializer
        //建立连接池
        requestConnect = Executors.newFixedThreadPool(maxConnectNumber);
        //建立socket连接
        serverSocket = new ServerSocket(port);

        logger.info(String.format("Server start success, listen on port %s.", port));

        while (running && serverSocket != null && !serverSocket.isClosed()) {
            try {
                Socket socket = serverSocket.accept();
                requestConnect.execute(new RequestHandler(socket, servletContext));
            } catch (SocketException socketException) {
                if (!running) {
                    break;
                }
                throw socketException;
            }
        }
    }

    /**
     * 容器销毁方法
     */
    public void dispose() {
        logger.info("Shutdown initiated...");
        running = false;
        if (serverSocket != null && !serverSocket.isClosed()) {
            try {
                serverSocket.close();
            } catch (IOException e) {
                logger.error("Socket close error.", e);
            }
        }
        if (!requestConnect.isShutdown()) {
            requestConnect.shutdown();
            try {
                // 等待 60 s
                if (!requestConnect.awaitTermination(60, TimeUnit.SECONDS)) {
                    // 如果未结束调用 shutdownNow 取消正在执行的任务
                    requestConnect.shutdownNow();
                    // 再次等待 60 s，如果还未结束，记录线程结束失败
                    if (!requestConnect.awaitTermination(60, TimeUnit.SECONDS)) {
                        logger.error("The connection pool is not down gracefully.");
                    }
                }
            } catch (InterruptedException ie) {
                requestConnect.shutdownNow();
            }
        }
        servletContext = null;
        logger.info("Shutdown completed.");
    }
}
